package cn.mw.cmdb.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.mw.cmdb.entity.AssetsDiscoverInfo;
import cn.mw.cmdb.enums.BatchScanStatusEnum;
import cn.mw.components.mongodb.tool.MongoUtils;
import cn.mw.microMonitorCommon.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class AssetsDiscoveryRunManage {

    private Map<String , AssetScanServiceContext> assetsDiscoveryTaskMap = new ConcurrentHashMap();

    private final String AssetsDiscoveryRunPrefix = "AssetsDiscovery:start:";

    private RedisUtils redisUtils;

    private long expireTime = 30;

    public AssetsDiscoveryRunManage(RedisUtils redisUtils){
        this.redisUtils = redisUtils;
    }

    public void startDiscovery(AssetsDiscoverInfo assetsDiscoverInfo){
        String key = AssetsDiscoveryRunPrefix + assetsDiscoverInfo.getId();
        AssetsDiscoverInfo status = new AssetsDiscoverInfo();

        //保存扫描信息到redis中,表示正在扫描
        String[] ignoreProperties = new String[]{MongoUtils.getFieldName(AssetsDiscoverInfo::getScanRules)};
        BeanUtil.copyProperties(assetsDiscoverInfo ,status ,ignoreProperties);
        status.setStatus(BatchScanStatusEnum.scanning.name());
        String json = JSONUtil.toJsonStr(status);
        redisUtils.set(key ,json ,expireTime , TimeUnit.SECONDS);
        log.info("startDiscovery {}" ,key);
    }


    public void finishDiscovery(AssetsDiscoverInfo assetsDiscoverInfo){
        String key = AssetsDiscoveryRunPrefix + assetsDiscoverInfo.getId();
        assetsDiscoverInfo.setProgress(100);
        String newStr = JSONUtil.toJsonStr(assetsDiscoverInfo);
        redisUtils.set(key ,newStr ,expireTime);
        log.info("finishDiscovery {}" ,key);
    }

    public void clearDiscovery(AssetsDiscoverInfo assetsDiscoverInfo){
        String key = AssetsDiscoveryRunPrefix + assetsDiscoverInfo.getId();
        redisUtils.del(key);
        log.info("clearDiscovery {}" ,key);
    }

    public void refreshExpireTime(AssetsDiscoverInfo assetsDiscoverInfo){
        String key = AssetsDiscoveryRunPrefix + assetsDiscoverInfo.getId();
        Object obj = redisUtils.get(key);
        if(null != obj) {
            String str = obj.toString();
            AssetsDiscoverInfo newValue = JSONUtil.toBean(str, AssetsDiscoverInfo.class);
            int progress = (null == newValue.getProgress() ? 0 : newValue.getProgress());
            double value = 10 + 0.9 * progress;
            Long newProgress = Math.round(value);
            newValue.setProgress(newProgress.intValue());

            String newStr = JSONUtil.toJsonStr(newValue);
            redisUtils.set(key, newStr, expireTime);
        }
    }

    public Map<String ,AssetsDiscoverInfo> getScaningAssetsDiscoverInfoMap(){
        Set<String> keys = redisUtils.keys(AssetsDiscoveryRunPrefix + "*");
        Map<String ,AssetsDiscoverInfo> ret = new HashMap<>();
        if(null != keys && !keys.isEmpty()){
            List<Object> list = redisUtils.getValues(new ArrayList<>(keys));
            if(null != list ){
                for(Object item : list){
                    AssetsDiscoverInfo assetsDiscoverInfo = JSONUtil.toBean(item.toString() ,AssetsDiscoverInfo.class);
                    ret.put(assetsDiscoverInfo.getId() ,assetsDiscoverInfo);
                }
            }
        }
        return ret;
    }

    public synchronized boolean hasTask(String scanRuleId){
        if (StrUtil.isBlank(scanRuleId)) {
            return false;
        }
        return null != assetsDiscoveryTaskMap.get(scanRuleId);
    }

    public synchronized boolean  checkAndAddTask(String scanRuleId ,AssetScanServiceContext assetScanServiceContext){
        if (StrUtil.isBlank(scanRuleId)) {
            return false;
        }
        boolean hasTask = null != assetsDiscoveryTaskMap.get(scanRuleId);
        if(!hasTask){
            assetsDiscoveryTaskMap.put(scanRuleId ,assetScanServiceContext);
        }

        return !hasTask;
    }

    public synchronized AssetScanServiceContext getTask(String scanRuleId){
        if (StrUtil.isBlank(scanRuleId)) {
            return null;
        }
        return assetsDiscoveryTaskMap.get(scanRuleId);
    }

    public synchronized void removeTask(String scanRuleId){
        if (StrUtil.isBlank(scanRuleId)) {
            return ;
        }
        assetsDiscoveryTaskMap.remove(scanRuleId);
    }
}
